package deployment

import (
	"github.com/pingcap/errors"
	"github.com/romberli/das/global"
	"github.com/romberli/das/internal/dependency/deployment"
	"github.com/romberli/go-util/constant"
	"github.com/romberli/go-util/middleware"
	"github.com/romberli/log"
)

var _ deployment.Repository = (*Repository)(nil)

type Repository struct {
	Database middleware.Pool
}

// NewRepository returns Repository with given middleware.Pool
func NewRepository(db middleware.Pool) *Repository {
	return newRepository(db)
}

// NewRepositoryWithGlobal returns Repository with global mysql pool
func NewRepositoryWithGlobal() *Repository {
	return newRepository(global.DASMySQLPool)
}

// newRepository returns *Repository with given middleware.Pool
func newRepository(db middleware.Pool) *Repository {
	return &Repository{db}
}

// Execute executes command with arguments on database
func (r *Repository) Execute(command string, args ...interface{}) (middleware.Result, error) {
	conn, err := r.Database.Get()
	if err != nil {
		return nil, err
	}
	defer func() {
		err = conn.Close()
		if err != nil {
			log.Errorf("deployment Repository.Execute(): close database connection failed.\n%+v", err)
		}
	}()

	return conn.Execute(command, args...)
}

// Transaction returns middleware.Transaction
func (r *Repository) Transaction() (middleware.Transaction, error) {
	return r.Database.Transaction()
}

// GetServerHostInfo gets the das server host info with given deployment region, deployment org and network zone
func (r *Repository) GetServerHostInfo(deploymentRegion, deploymentOrg, networkZone string) (string, error) {
	sql := `SELECT host_info FROM t_sys_deployment_info
            WHERE del_flag = 0 AND deployment_region = ? AND deployment_org = ? AND network_zone = ?`
	log.Debugf("deployment Repository.GetDASServerAddr(): sql: %s, placeholders: %s, %s, %s", sql, deploymentRegion, deploymentOrg, networkZone)

	result, err := r.Execute(sql, deploymentRegion, deploymentOrg, networkZone)
	if err != nil {
		return constant.EmptyString, err
	}

	switch result.RowNumber() {
	case 0:
		return constant.EmptyString, errors.Errorf(
			"deployment Repository.GetDASServerAddr(): data does not exist. deploymentRegion: %s, deploymentOrg: %s, networkZone: %s",
			deploymentRegion, deploymentOrg, networkZone)
	case 1:
		return result.GetString(constant.ZeroInt, constant.ZeroInt)
	default:
		return constant.EmptyString, errors.Errorf("deployment Repository.GetDASServerAddr(): duplicate key exists. deploymentRegion: %s, deploymentOrg: %s, networkZone: %s",
			deploymentRegion, deploymentOrg, networkZone)
	}
}

// GetRemotePath gets the remote das path with given local path
func (r *Repository) GetRemotePath(localPath string) (string, error) {
	sql := `SELECT remote_path FROM t_sys_path_map WHERE del_flag = 0 AND local_path = ?`
	log.Debugf("deployment Repository.GetRemotePath(): sql :%s, placeholders: %s", sql, localPath)

	result, err := r.Execute(sql, localPath)
	if err != nil {
		return constant.EmptyString, err
	}

	switch result.RowNumber() {
	case 0:
		return constant.EmptyString, errors.Errorf(
			"deployment Repository.GetRemotePath(): data does not exist. localPath: %s", localPath)
	case 1:
		return result.GetString(constant.ZeroInt, constant.ZeroInt)
	default:
		return constant.EmptyString, errors.Errorf("deployment Repository.GetRemotePath(): duplicate key exists. localPath: %s", localPath)
	}
}
